/*
 * jngc, Java utility classes by Nicholas Coltharp
 * Copyright (C) 2010 Nicholas Coltharp <ngc1@rice.edu>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package edu.rice.ngc1.util;

import java.io.Serializable;

/**
 * <p>
 * Helps with common implementations of {@link Object#equals(Object)}.
 * </p>
 * 
 * <p>
 * In most cases, {@code equals()} can be implemented in four steps:
 * <ol>
 * <ul>
 * if the given object is the same object as {@code this}, return
 * {@code true};
 * </ul>
 * <ul>
 * if the given object is {@code null}, return {@code false};
 * </ul>
 * <ul>
 * if the given object's class is not the same as this object's class,
 * return {@code false};
 * </ul>
 * <ul>
 * finally, compare the two objects based on their fields and return
 * accordingly.
 * </ul>
 * </ol>
 * This class provides an implementation of the first three parts,
 * allowing implementing classes to focus on the fourth part.
 * </p>
 * 
 * @param <T>
 *            the type of object that this object is helping with
 *            implementing {@code equals()}
 */
public class EqualsHelper<T> implements Cloneable, Serializable {

    /**
     * Serial version UID.
     */
    private static final long serialVersionUID = -3778327420158515966L;

    /**
     * The object that this object is helping implement
     * {@code equals()}.
     */
    private final T self;

    /**
     * Creates a new {@code EqualsHelper} which will help compare the
     * given object.
     * 
     * @param self
     *            the object to help compare; should not be
     *            {@code null}
     */
    public EqualsHelper(T self) {
        this.self = self;
    }

    /**
     * Gets the object that was provided to this helper at
     * construction time.
     * 
     * @return the object provided to this helper at construction time
     */
    public T getObject() {
        return self;
    }

    @Override
    public EqualsHelper<T> clone() {
        return new EqualsHelper<T>(self);
    }

    /**
     * Indicates whether the object provided to this helper at
     * construction time is equivalent to the given object according
     * to the first three requirements of {@code equals()}.
     * 
     * @param other
     *            the object to compare against
     * @return {@code other}, casted to {@code T}, if it satisfies the
     *         requirements; {@code null} otherwise
     */
    public T check(Object other) {
        return check(self, other);
    }

    /**
     * Indicates whether the two given objects are equal by the first
     * three requirements of {@code equals()}.
     * 
     * @param <T>
     *            the type of {@code self}
     * @param self
     *            the "reference" object; should not be {@code null}
     * @param obj
     *            the "other" object
     * @return {@code obj}, casted to {@code T}, if it satisfies the
     *         requirements; {@code null} otherwise
     */
    @SuppressWarnings("unchecked")
    public static <T> T check(T self, Object obj) {
        if (obj == self) {
            return (T) obj;
        }
        if (obj == null || obj.getClass() != self.getClass()) {
            return null;
        }
        return (T) obj;
    }
}
